package cc.siyecao.mapper.conditions;

import cc.siyecao.mapper.common.util.StringUtils;
import cc.siyecao.mapper.provider.entity.EntityColumn;
import cc.siyecao.mapper.provider.entity.EntityFactory;
import cc.siyecao.mapper.provider.entity.EntityTable;
import cc.siyecao.mapper.util.MetaObjectUtil;
import org.apache.ibatis.reflection.MetaObject;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;

/**
 * 查询条件封装
 * <p>比较值</p>
 */
public interface Compare<W, R, T> extends StringCompare<W> {

    /**
     * 将此对象的所有字段参数作为相等查询条件，如果字段为 null，则为 is null
     *
     * @param entity 参数对象
     */
    default W allEq(T entity) {
        if (entity == null) {
            return (W) this;
        }
        EntityTable entityTable = EntityFactory.create( entity.getClass() );
        Map<String, EntityColumn> propertyMap = entityTable.propertyMap();
        MetaObject metaObject = MetaObjectUtil.forObject( entity );
        String[] properties = metaObject.getGetterNames();
        for (String property : properties) {
            //属性和列对应Map中有此属性
            EntityColumn column = propertyMap.get( property );
            if (column != null) {
                Object value = metaObject.getValue( property );
                //属性值不为空
                if (value != null) {
                    eq( column, value );
                } else {
                    isNull( column );
                }
            }
        }
        return (W) this;
    }

    /**
     * 将此对象的不为空的字段参数作为相等查询条件
     *
     * @param entity 参数对象
     * @author Bob {@link}0haizhu0@gmail.com
     * @Date 2015年7月17日 下午12:48:08
     */
    default W eq(T entity) {
        if (entity == null) {
            return (W) this;
        }
        EntityTable entityTable = EntityFactory.create( entity.getClass() );
        Map<String, EntityColumn> propertyMap = entityTable.propertyMap();
        MetaObject metaObject = MetaObjectUtil.forObject( entity );
        String[] properties = metaObject.getGetterNames();
        for (String property : properties) {
            //属性和列对应Map中有此属性
            EntityColumn column = propertyMap.get( property );
            if (column != null) {
                Object value = metaObject.getValue( property );
                //属性值不为空
                if (value != null) {
                    eq( column, value );
                }
            }
        }
        return (W) this;
    }

    /**
     * 等于 =
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W eq(EntityColumn column, Object val) {
        return eq( true, column, val );
    }

    /**
     * 等于 =
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    W eq(boolean condition, EntityColumn column, Object val);

    /**
     * 等于 =
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W eqIfPresent(R column, Object val) {
        return eq( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * 等于 =
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W eq(R column, Object val) {
        return eq( true, column, val );
    }

    /**
     * 等于 =
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W eq(boolean condition, R column, Object val);

    /**
     * 不等于 &lt;&gt;
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W ne(R column, Object val) {
        return ne( true, column, val );
    }

    /**
     * 不等于 &lt;&gt;
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W neIfPresent(R column, Object val) {
        return ne( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * 不等于 &lt;&gt;
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W ne(boolean condition, R column, Object val);

    /**
     * 大于 &gt;
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W gt(R column, Object val) {
        return gt( true, column, val );
    }

    /**
     * 大于 &gt;
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W gtIfPresent(R column, Object val) {
        return gt( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * 大于 &gt;
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W gt(boolean condition, R column, Object val);

    /**
     * 大于等于 &gt;=
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W ge(R column, Object val) {
        return ge( true, column, val );
    }

    /**
     * 大于等于 &gt;=
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W geIfPresent(R column, Object val) {
        return ge( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * 大于等于 &gt;=
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W ge(boolean condition, R column, Object val);

    /**
     * 小于 &lt;
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W lt(R column, Object val) {
        return lt( true, column, val );
    }

    /**
     * 小于 &lt;
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W ltIfPresent(R column, Object val) {
        return lt( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * 小于 &lt;
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W lt(boolean condition, R column, Object val);

    /**
     * 小于等于 &lt;=
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W le(R column, Object val) {
        return le( true, column, val );
    }

    /**
     * 小于等于 &lt;=
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W leIfPresent(R column, Object val) {
        return le( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * 小于等于 &lt;=
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W le(boolean condition, R column, Object val);

    /**
     * BETWEEN 值1 AND 值2
     *
     * @param column 字段
     * @param val1   值1
     * @param val2   值2
     * @return children
     */
    default W between(R column, Object val1, Object val2) {
        return between( true, column, val1, val2 );
    }

    /**
     * BETWEEN 值1 AND 值2
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val1      值1
     * @param val2      值2
     * @return children
     */
    W between(boolean condition, R column, Object val1, Object val2);

    /**
     * NOT BETWEEN 值1 AND 值2
     *
     * @param column 字段
     * @param val1   值1
     * @param val2   值2
     * @return children
     */
    default W notBetween(R column, Object val1, Object val2) {
        return notBetween( true, column, val1, val2 );
    }

    /**
     * NOT BETWEEN 值1 AND 值2
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val1      值1
     * @param val2      值2
     * @return children
     */
    W notBetween(boolean condition, R column, Object val1, Object val2);

    /**
     * LIKE '%值%'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W like(R column, Object val) {
        return like( true, column, val );
    }

    /**
     * LIKE '%值%'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W likeIfPresent(R column, Object val) {
        return like( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * LIKE '%值%'
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W like(boolean condition, R column, Object val);

    /**
     * NOT LIKE '%值%'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W notLike(R column, Object val) {
        return notLike( true, column, val );
    }

    /**
     * NOT LIKE '%值%'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W notLikeIfPresent(R column, Object val) {
        return notLike( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * NOT LIKE '%值%'
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W notLike(boolean condition, R column, Object val);

    /**
     * NOT LIKE '%值'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W notLikeLeft(R column, Object val) {
        return notLikeLeft( true, column, val );
    }

    /**
     * NOT LIKE '%值'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W notLikeLeftIfPresent(R column, Object val) {
        return notLikeLeft( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * NOT LIKE '%值'
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W notLikeLeft(boolean condition, R column, Object val);

    /**
     * NOT LIKE '值%'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W notLikeRight(R column, Object val) {
        return notLikeRight( true, column, val );
    }

    /**
     * NOT LIKE '值%'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W notLikeRightIfPresent(R column, Object val) {
        return notLikeRight( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * NOT LIKE '值%'
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W notLikeRight(boolean condition, R column, Object val);

    /**
     * LIKE '%值'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W likeLeft(R column, Object val) {
        return likeLeft( true, column, val );
    }

    /**
     * LIKE '%值'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W likeLeftIfPresent(R column, Object val) {
        return likeLeft( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * LIKE '%值'
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W likeLeft(boolean condition, R column, Object val);

    /**
     * LIKE '值%'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W likeRight(R column, Object val) {
        return likeRight( true, column, val );
    }

    /**
     * LIKE '值%'
     *
     * @param column 字段
     * @param val    值
     * @return children
     */
    default W likeRightIfPresent(R column, Object val) {
        return likeRight( StringUtils.checkValNotNull( val ), column, val );
    }

    /**
     * LIKE '值%'
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param val       值
     * @return children
     */
    W likeRight(boolean condition, R column, Object val);

    /**
     * 字段 IS NULL
     * <p>例: isNull("name")</p>
     *
     * @param column 字段
     * @return children
     */
    default W isNull(EntityColumn column) {
        return isNull( true, column );
    }

    /**
     * 字段 IS NULL
     * <p>例: isNull("name")</p>
     *
     * @param column 字段
     * @return children
     */
    W isNull(boolean condition, EntityColumn column);

    /**
     * 字段 IS NULL
     * <p>例: isNull("name")</p>
     *
     * @param column 字段
     * @return children
     */
    default W isNull(R column) {
        return isNull( true, column );
    }

    /**
     * 字段 IS NULL
     * <p>例: isNull("name")</p>
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @return children
     */
    W isNull(boolean condition, R column);

    /**
     * 字段 IS NOT NULL
     * <p>例: isNotNull("name")</p>
     *
     * @param column 字段
     * @return children
     */
    default W isNotNull(R column) {
        return isNotNull( true, column );
    }

    /**
     * 字段 IS NOT NULL
     * <p>例: isNotNull("name")</p>
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @return children
     */
    W isNotNull(boolean condition, R column);

    /**
     * 字段 IN (value.get(0), value.get(1), ...)
     * <p>例: in("id", Arrays.asList(1, 2, 3, 4, 5))</p>
     *
     * <li> 注意！集合为空若存在逻辑错误，请在 condition 条件中判断 </li>
     * <li> 如果集合为 empty 则不会进行 sql 拼接 </li>
     *
     * @param column 字段
     * @param coll   数据集合
     * @return children
     */
    default W in(R column, Collection<?> coll) {
        return in( true, column, coll );
    }

    /**
     * 字段 IN (value.get(0), value.get(1), ...)
     * <p>例: in("id", Arrays.asList(1, 2, 3, 4, 5))</p>
     *
     * @param column 字段
     * @param coll   值
     * @return children
     */
    default W inIfPresent(R column, Collection<?> coll) {
        return in( StringUtils.isNotEmpty( coll ), column, coll );
    }

    /**
     * 字段 IN (value.get(0), value.get(1), ...)
     * <p>例: in("id", Arrays.asList(1, 2, 3, 4, 5))</p>
     *
     * <li> 注意！集合为空若存在逻辑错误，请在 condition 条件中判断 </li>
     * <li> 如果集合为 empty 则不会进行 sql 拼接 </li>
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param coll      数据集合
     * @return children
     */
    W in(boolean condition, R column, Collection<?> coll);

    /**
     * 字段 IN (v0, v1, ...)
     * <p>例: in("id", 1, 2, 3, 4, 5)</p>
     *
     * <li> 注意！数组为空若存在逻辑错误，请在 condition 条件中判断 </li>
     * <li> 如果动态数组为 empty 则不会进行 sql 拼接 </li>
     *
     * @param column 字段
     * @param values 数据数组
     * @return children
     */
    default W in(R column, Object... values) {
        return in( true, column, values );
    }

    /**
     * 字段 IN (v0, v1, ...)
     * <p>例: in("id", 1, 2, 3, 4, 5)</p>
     *
     * @param column 字段
     * @param values 值
     * @return children
     */
    default W inIfPresent(R column, Object... values) {
        return in( StringUtils.isNotEmpty( values ), column, values );
    }

    /**
     * 字段 IN (v0, v1, ...)
     * <p>例: in("id", 1, 2, 3, 4, 5)</p>
     *
     * <li> 注意！数组为空若存在逻辑错误，请在 condition 条件中判断 </li>
     * <li> 如果动态数组为 empty 则不会进行 sql 拼接 </li>
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param values    数据数组
     * @return children
     */
    W in(boolean condition, R column, Object... values);

    /**
     * 字段 NOT IN (value.get(0), value.get(1), ...)
     * <p>例: notIn("id", Arrays.asList(1, 2, 3, 4, 5))</p>
     *
     * @param column 字段
     * @param coll   数据集合
     * @return children
     */
    default W notIn(R column, Collection<?> coll) {
        return notIn( true, column, coll );
    }

    /**
     * 字段 NOT IN (value.get(0), value.get(1), ...)
     * <p>例: notIn("id", Arrays.asList(1, 2, 3, 4, 5))</p>
     *
     * @param column 字段
     * @param coll   值
     * @return children
     */
    default W notInIfPresent(R column, Collection<?> coll) {
        return notIn( StringUtils.isNotEmpty( coll ), column, coll );
    }

    /**
     * 字段 NOT IN (value.get(0), value.get(1), ...)
     * <p>例: notIn("id", Arrays.asList(1, 2, 3, 4, 5))</p>
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param coll      数据集合
     * @return children
     */
    W notIn(boolean condition, R column, Collection<?> coll);

    /**
     * 字段 NOT IN (v0, v1, ...)
     * <p>例: notIn("id", 1, 2, 3, 4, 5)</p>
     *
     * @param column 字段
     * @param values 数据数组
     * @return children
     */
    default W notIn(R column, Object... values) {
        return notIn( true, column, values );
    }

    /**
     * 字段 NOT IN (v0, v1, ...)
     * <p>例: notIn("id", 1, 2, 3, 4, 5)</p>
     *
     * @param column 字段
     * @param values 值
     * @return children
     */
    default W notInIfPresent(R column, Object... values) {
        return notIn( StringUtils.isNotEmpty( values ), column, values );
    }

    /**
     * 字段 NOT IN (v0, v1, ...)
     * <p>例: notIn("id", 1, 2, 3, 4, 5)</p>
     *
     * @param condition true：执行条件  false：忽略条件
     * @param column    字段
     * @param values    数据数组
     * @return children
     */
    W notIn(boolean condition, R column, Object... values);

}
